home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Educational / Ortografie / Ortografie.app / PlayerControl.m < prev    next >
Text File  |  1995-09-01  |  9KB  |  390 lines

  1. // Copyright (95) by melonSoft Ralf Suckow Berlin, All Rights Reserved
  2. //
  3. // You may freely copy, distribute, and reuse the code in this example.
  4. // Ralf Suckow disclaims any warranty of any kind, expressed or  
  5. // implied, as to its fitness for any particular use.
  6.  
  7. #import "PlayerControl.h"
  8. #import <strings.h>
  9. #import <sound/accesssound.h>
  10. #import <sound/performsound.h>
  11.  
  12. #define SAVEDFILENAME      "Library/Ortografie/words.orth"
  13. #define CREATESAVEDFILEDIR "mkdirs ~/Library/Ortografie"
  14.  
  15. @implementation PlayerControl
  16.  
  17. - appDidInit:sender
  18. {
  19.   NXTypedStream * infile;
  20.   char filename[1024];
  21.   
  22.   // looking up an existing file in users library
  23.   sprintf (filename, "%s/%s", NXHomeDirectory (), SAVEDFILENAME);
  24.   infile = NXOpenTypedStreamForFile (filename, NX_READONLY);
  25.   
  26.   if (!infile) {
  27.     // creating new sound list
  28.     sounds = [[List alloc] init];
  29.   }
  30.   else {
  31.     // loading old file
  32.     sounds = NXReadObject (infile);
  33.     // update browser
  34.     [browser loadColumnZero];
  35.     NXCloseTypedStream (infile);
  36.   }
  37.  
  38.   currentSound = nil;
  39.   askingFor = nil;
  40.   previousAsked = nil;
  41.   SNDReserve(SND_ACCESS_IN | SND_ACCESS_OUT, 0);
  42.   return self;
  43. }
  44.  
  45. - next:sender
  46. {
  47.   id next;
  48.   
  49.   if ([sounds count] == 0) {
  50.   
  51. #define NEXT_WORD NXLocalizedString ("NextWord", NULL, goto next word action)
  52. #define NO_WORDS NXLocalizedString ("NoWords", NULL, no words found problem)
  53.                           
  54.     NXRunAlertPanel (NEXT_WORD, NO_WORDS, NULL, NULL, NULL);
  55.     return nil;
  56.   }
  57.   
  58.   if (askingFor)
  59.     [self playSoundNamed:"erst_loesen"];
  60.   else {
  61.   
  62.     // looking for a new word to ask for
  63.     if ([sounds count] == 1)
  64.       next = [sounds objectAt:0];
  65.     else
  66.       while ((next = [sounds objectAt:random() % [sounds count]]) 
  67.                                                           == previousAsked)
  68.         ;
  69.   
  70.     askingFor = next;
  71.     [self same:self];
  72.   }
  73.   return self;
  74. }
  75.  
  76. - same:sender
  77. {
  78.   // ask for same work
  79.  
  80.   if (askingFor) {
  81.     switch (random () % 3) {
  82.       case 0: [self playSoundNamed:"schreibe_wort"];  break;
  83.       case 1: [self playSoundNamed:"schreibe_bitte"]; break;
  84.       case 2: [self playSoundNamed:"naechstes_wort"]; break;
  85.     }
  86.     [self playSound:askingFor];
  87.     [[text setStringValue:""] selectText:self];
  88.   }
  89.   else
  90.     [self playSoundNamed:"nichts_gesagt"];
  91.     
  92.   return self;
  93. }
  94.  
  95. - help:sender
  96. {   
  97.   if (askingFor) {
  98.     [rightText setStringValue:[askingFor name]];
  99.     [rightPanel makeKeyAndOrderFront:self];
  100.     [NXApp runModalFor:rightPanel];
  101.     [rightPanel orderOut:self];
  102.   }
  103.   else
  104.     [self playSoundNamed:"druecke_next"];
  105.   
  106.   return self;
  107. }
  108.  
  109. - closeHelp:sender
  110. {
  111.   [NXApp stopModal];
  112.   return self;
  113. }
  114.  
  115. - ready:sender
  116. {
  117.   // check word
  118.   
  119.   if (askingFor) {
  120.     if (!strcmp ([askingFor name], [text stringValue])) {
  121.       switch (random () % 5) {
  122.         case 0: [self playSoundNamed:"sehr_gut"];    break;
  123.         case 1: [self playSoundNamed:"gut_gemacht"]; break;
  124.         case 2: [self playSoundNamed:"einwandfrei"]; break;
  125.         case 3: [self playSoundNamed:"otlitschno"];  break;
  126.         case 4: [self playSoundNamed:"richtig"];     break;
  127.       }
  128.       if ([askingFor info])
  129.         * (int *) [askingFor info] += 1;
  130.       previousAsked = askingFor;
  131.       askingFor = nil;
  132.     }
  133.     else {
  134.       switch (random () % 4) {
  135.         case 0: [self playSoundNamed:"falsch"];     break;
  136.         case 1: [self playSoundNamed:"nochmal"];    break;
  137.         case 2: [self playSoundNamed:"denk_nach"];  break;
  138.         case 3: [self playSoundNamed:"noch_nicht"]; break;
  139.       }
  140.       if ([askingFor info])
  141.         * (int *) [askingFor info] = 0;
  142.     }
  143.     [[browser loadColumnZero] display];
  144.   }
  145.   else
  146.     [self playSoundNamed:"druecke_next"];
  147.   
  148.   return self;
  149. }
  150.  
  151. - add:sender
  152. {
  153.   int     row;
  154.   Sound * sound;
  155.   const char * name;
  156.   
  157.   if (!strcmp ([newText stringValue], "")) {
  158.  
  159. #define ADD_WORD NXLocalizedString ("AddingWord", NULL, add word action)
  160. #define NO_NAME NXLocalizedString ("TypeIn", NULL, word not typed in problem)
  161.                           
  162.     NXRunAlertPanel (ADD_WORD, NO_NAME, NULL, NULL, NULL);
  163.     return nil;
  164.   }
  165.  
  166.   // looking for existing sound
  167.   name = [newText stringValue];
  168.   for (row = 0; row < [sounds count]; row ++)
  169.     if (!strcmp (name, [[sounds objectAt:row] name]))
  170.       break;
  171.       
  172.   if (row != [sounds count]) { // gefunden
  173.  
  174. #define DUP_WORD NXLocalizedString ("IsInList", NULL, duplication problem)
  175. #define AHA_ANSWER NXLocalizedString ("Indeed", NULL, a positive answer)
  176.                           
  177.     NXRunAlertPanel (ADD_WORD, DUP_WORD, AHA_ANSWER, NULL, NULL);
  178.     [browser scrollColumnToVisible:row];
  179.     return nil;
  180.   }
  181.   
  182.   if (!(sound = [[Sound alloc] init])) {
  183.  
  184. #define NO_NEW_SND NXLocalizedString ("NoNewSnd", NULL, no new sound problem)
  185.                           
  186.     NXRunAlertPanel (ADD_WORD, NO_NEW_SND, NULL, NULL, NULL);
  187.     return nil;
  188.   }
  189.  
  190.   [sound setName:name];
  191.   [sounds addObject:sound];
  192.   [browser loadColumnZero];
  193.   currentSound = sound;
  194.   [[browser matrixInColumn:0] selectCellAt:row :0];
  195.   [browser scrollColumnToVisible:row];
  196.   [newText selectText:self];
  197.   return self;
  198. }
  199.  
  200. - remove:sender
  201. {
  202.   if (currentSound)
  203.     [self stop:self];
  204.   
  205.   [[sounds removeObject:currentSound] free];
  206.   currentSound = nil;
  207.   [newText setStringValue:""];
  208.   [browser loadColumnZero];
  209.   return self;
  210. }
  211.  
  212. - browserClicked:sender
  213. {
  214.   int row;
  215.   
  216.   row = [[browser matrixInColumn:0] selectedRow];
  217.   currentSound = [sounds objectAt:row];
  218.   [newText setStringValue:[currentSound name]];
  219.   return self;
  220. }
  221.  
  222. - play:sender
  223. {
  224.   if (currentSound)
  225.     [self playSound:currentSound];
  226.  
  227.   return self;
  228. }
  229.  
  230. - stop:sender
  231. {
  232.    if (currentSound /* && [recordButton state] */)
  233.      [currentSound stop:sender];
  234.  
  235.    return self;
  236. }
  237.  
  238. - record:sender
  239.   // two attempts for avoiding Mach Kernel Errors
  240.  
  241.   int err;
  242.   
  243.   if (currentSound) {
  244.     [recordButton setEnabled:NO];
  245.     [playButton   setEnabled:NO];
  246.     
  247.     // The second recording doesn't work.
  248.     // The structure, in fact, is emptied with deleteSamples,
  249.     // but when you record again, a part of the
  250.     // old sound is intermixed/overlayed with the new.
  251.     // I don't have an idea what to do.
  252.     
  253.     [currentSound deleteSamples]; 
  254.     
  255.     if ([[currentSound setDelegate:self] record]) 
  256.       if (err = [currentSound record]) {
  257.  
  258. #define RECORDING NXLocalizedString ("Recording", NULL, recording action)
  259. #define SOUND_ERROR NXLocalizedString ("SndError", NULL, sound error: description)
  260.                           
  261.         NXRunAlertPanel (RECORDING, SOUND_ERROR, NULL, NULL, NULL,
  262.                          SNDSoundError(err));
  263.  
  264.         [self didRecord:self];
  265.       }
  266.   }
  267.   else {
  268.  
  269. #define SELECT_ENTER NXLocalizedString ("SelectOrEnter", NULL, no word selected to be recorded)
  270.                           
  271.     NXRunAlertPanel (RECORDING, SELECT_ENTER, NULL, NULL, NULL);
  272.     [recordButton setState:0];
  273.   }
  274.   
  275.   return self;
  276. }
  277.  
  278. - playSound:sound
  279. /*
  280. **  Synchroneous Playing -- two attempts for avoiding Mach Kernel Errors
  281. */
  282.   SNDSoundStruct * s;
  283.   int err;
  284.   
  285.   s = [sound soundStruct];
  286.   err = SNDStartPlaying (s, 1, 0, 0, SND_NULL_FUN, SND_NULL_FUN);
  287.   
  288.   if (err)
  289.     err = SNDStartPlaying (s, 1, 0, 0, SND_NULL_FUN, SND_NULL_FUN);
  290.    
  291.   if (err)
  292.  
  293. #define PLAYBACK NXLocalizedString ("Playback", NULL, playback action)
  294.  
  295.     NXRunAlertPanel (PLAYBACK, SOUND_ERROR, NULL, NULL, NULL,
  296.                      SNDSoundError(err));
  297.  
  298.   else
  299.     SNDWait (1);
  300.   
  301.   return self;
  302. }
  303.  
  304. - didRecord:sender
  305. {
  306.   if ([recordButton state]) {
  307.     [[recordButton setState:0] setEnabled:YES];
  308.     [playButton setEnabled:YES];
  309.   }
  310.   return self;
  311. }
  312.  
  313. - hadError:sender
  314. {
  315.   int err;
  316.   
  317.   err = [[sender soundBeingProcessed] processingError];
  318.  
  319. #define PROBLEM NXLocalizedString ("Problem", NULL, problematic action)
  320.                           
  321.   NXRunAlertPanel (PROBLEM, SOUND_ERROR, NULL, NULL, NULL, 
  322.                    SNDSoundError(err));
  323.   [self didRecord:self];
  324.   return self;
  325. }
  326.  
  327. - save:sender
  328. {
  329.   NXTypedStream * outfile;
  330.   char filename[1024];
  331.  
  332.   sprintf (filename, "%s/%s", NXHomeDirectory (), SAVEDFILENAME);
  333.   outfile = NXOpenTypedStreamForFile (filename, NX_WRITEONLY);
  334.   
  335.   if (!outfile) {
  336.     system (CREATESAVEDFILEDIR);
  337.     outfile = NXOpenTypedStreamForFile (filename, NX_WRITEONLY);
  338.   }
  339.   
  340.   if (!outfile)
  341.   
  342. #define SAVING NXLocalizedString ("Saving", NULL, saving action)
  343. #define CANNOT_OPEN NXLocalizedString ("CannotOpen", NULL, cannot open: filename)
  344.                           
  345.     NXRunAlertPanel (SAVING, CANNOT_OPEN, NULL, NULL, NULL, filename);
  346.   else {
  347.     NXWriteRootObject (outfile, sounds);
  348.     NXCloseTypedStream (outfile);
  349.   }
  350.  
  351.   return self;
  352. }
  353.  
  354. - playSoundNamed:(const char *)name
  355. {
  356.   return [self playSound:[Sound findSoundFor:name]];
  357. }
  358.  
  359. // browser delegate methods (a very lazy delegate)
  360.  
  361. - (int)browser:sender getNumRowsInColumn:(int)column
  362. {
  363.   if (column == 0)
  364.     return [sounds count];
  365.   else
  366.     return 0;
  367. }
  368.  
  369. - browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
  370. {
  371.   id   sound;
  372.   char toDisplay[1024];
  373.   int  * infoPtr;
  374.   
  375.   sound = [sounds objectAt:row];
  376.   infoPtr = (int *) [sound info];
  377.   sprintf (toDisplay, "%-3d  %s", infoPtr? *infoPtr : 0, [sound name]);
  378.   
  379.   [[[[cell setLoaded:YES] 
  380.            setLeaf:YES]
  381.            setStringValue:toDisplay]
  382.            setEnabled:YES];
  383.            
  384.   return self;
  385. }
  386.  
  387. @end
  388.